# 'Friendly Flow' is a Server Framework for Python 2.5 and up
# Copyright (C) Xaba Software http://www.xaba.nl/
#
# This file is part of 'Friendly Flow'
#
# 'Friendly Flow' is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# 'Friendly Flow' is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with 'Friendly Flow'; if not, write to the Free Software
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

from friendlyflow import LineReader, socket, RETURN

CRLF = '\r\n'

class HttpError(Exception):
    def __init__(self, code, message):
        self._code = code
        self._message = message

class HttpRequest(object):
    
    def __init__(self, sock, remoteAddress):
        self._sock = LineReader(socket(sock))
        self._remoteAddress = remoteAddress
        self._requestLine = None
        self._path = None
        self._command = None
        self._version = None
        
        self._responeLineWritten = False
        
    #Request Accessors:
    def command(self):
        if not self._command:
            yield self._parseRequestLine()
        yield RETURN(self._command)
    
    def path(self):
        if not self._path:
            yield self._parseRequestLine()
        yield RETURN(self._path)

    def version(self):
        if not self._version:
            yield self._parseRequestLine()
        yield RETURN(self._version)

    #Response Accessors
    def writeResponseLine(self, code, message):
        #TODO response lines are not required for version 0.9
        #TODO test you can't do this twice...
        self._responeLineWritten = True
        yield self._sock.writeAll(self._version + " " + str(code) + " " + message + CRLF)

    def writeAll(self, data):
        if not self._responeLineWritten:
            yield self.writeResponseLine(200, "OK")
            yield self._sock.writeAll(CRLF)
        yield self._sock.writeAll(data)

    #Request Parsing
    def _parseRequestLine(self):
        self._requestLine = yield self._sock.readLine()
        if not self._requestLine:
            raise HttpError(400, "No Request Line")
        
        parts = self._requestLine.split()
        if len(parts) == 3:
            self._command, self._path, self._version = parts
            if self._version[:5] != 'HTTP/':
                raise HttpError(400, "Bad request version (%s)" % self._version)
            try:
                versionRhs = self._version.split('/', 1)[1]
                parsedVersion = versionRhs.split(".")
                if len(parsedVersion) != 2:
                    raise HttpError(400, "Bad request version (%s)" % self._version)
                parsedVersion = int(parsedVersion[0]), int(parsedVersion[1])
            except (ValueError, IndexError):
                raise HttpError(400, "Bad request version (%s)" % self._version)

            if parsedVersion >= (2, 0):
                raise HttpError(505, "Invalid HTTP Version (%s)" % self._version)
        
        elif len(parts) == 2:
            pass #TODO impol. 0.9
        else:
            pass #TODO corner cases

        
#keep-alive is as of yet... too complicated... try one request per connection first.